//
//  ViewController.swift
//  swift-array
//
//  Created by Lejia on 2018/9/11.
//  Copyright © 2018年 lejias. All rights reserved.
//

import UIKit

class ViewController: UIViewController {


    override func viewDidLoad() {
        super.viewDidLoad()
        self.view.backgroundColor = UIColor.white
        /*
         * 数组和可变性
         */
//        letAndVar()
//        mutableExample()
        
        /*
         * 数组和可选值
         */
//        arrayOption()
        
        /*
         * 数组变形
         */
//        arrayMap()
        changeArray()
    }
    
    //TODO: - 数组和可变性
    func letAndVar() {
        /*
         * 使用 let 定义的变量因为其具有不变性，因此更有理由被优先使用。当你读到类似 let arr = ... 这样的声明时，你可以确定 arr 的值将永远不变，这一点是由编译器强制保证的。
         * 这在你需要通读代码的时候会很有帮助。
         * 不过，要注意这只针对那些具有值语义的类型。
         * 使用 let 定义的类实例对象 (也就是说对于引用类型) 时，它保证的是这个引用永远不会发生变化，你不能再给这个引用赋一个新的值，但是这个引用所指向的对象却是可以改变的
         */
        let arr = [0, 1, 2, 3, 5]
        /*
         * arr 使用let声明的常量  不可变
         */
        //        arr.append(4)
        print(arr)//[0, 1, 2, 3, 5]
        
        
        var mutableArr = [0, 1, 1, 2, 3, 5]
        
        mutableArr.append(8)
        mutableArr.append(contentsOf: [13, 21])
        print(mutableArr)//[0, 1, 1, 2, 3, 5, 8, 13, 21]
    }
    
    func mutableExample() {
        /*
         * var y = x 语句复制了 x，所以在将 4 添加到 y 末尾的时候，x 并不会发生改变，它的值依然是 [1,2,3]。当你把一个数组传递给一个函数时，会发生同样的事情；方法将得到这个数组的一份本地复制，所有对它的改变都不会影响调用者所持有的数组
         */
        var x = [1, 2, 3]
        var y = x
        y.append(4)
        print("x = \(x) y = \(y)")//x = [1, 2, 3] y = [1, 2, 3, 4]
        x.append(5)
        print("x = \(x) y = \(y)")//x = [1, 2, 3, 5] y = [1, 2, 3, 4]

        /*
         * 对比一下 Foundation 框架中 NSArray 在可变特性上的处理方法。NSArray 中没有更改方法，想要更改一个数组，你必须使用 NSMutableArray。但是，就算你拥有的是一个不可变的 NSArry，但是它的引用特性并不能保证这个数组不会被改变
         */
        let a = NSMutableArray(array: [1, 2, 3])
        let b: NSArray = a
        a.insert(5, at: 0)
        print("a = \(a)  b = \(b)") // a = (5, 1, 2, 3) b = (5, 1, 2, 3)
        
        let c = NSMutableArray(array: [1, 2, 3])
        let d = c.copy()
        c.insert(0, at: 0)
        print("c = \(c) d = \(d)") //c = (0, 1, 2, 3) d = (1, 2, 3)
    }
    
    
    //TODO: - 数组和可选值
    func arrayOption () {
        let arr = [1, 2, 3]
        print("arr.count = \(arr.count) arr.isEmpty = \(arr.isEmpty)")
        
        for item in arr {
            print(item) //1 2 3
        }
        print("---------------------------------------")

        /*
         * 想要迭代除了第一个元素以外的数组其余部分
         */
        for item in arr.dropFirst() {
            print(item) //2 3
        }
        print("---------------------------------------")

        /*
         * 想要迭代除了前两个元素以外的数组其余部分
         */
        for item in arr.dropFirst(2) {
            print(item) //3
        }
        print("---------------------------------------")
        
        /*
         * 想要迭代除了最后一个元素以外的数组
         */
        for item in arr.dropLast() {
            print(item) //1 2
        }
        
        /*
         * 想要迭代除了最后 5 个元素以外的数组
         */
        for item in arr.dropLast(5) {
            print(item) //
        }
        print("---------------------------------------")
        
        /*
         * 想要列举数组中的元素和对应的下标
         */
        for (index, item) in arr.enumerated() {
            print("index = \(index)  item = \(item)") //index = 0  item = 1  index = 1  item = 2  index = 2  item = 3
        }
        
//        if let index = arr.index { someMatchingLogic($0) } {
//
//        }
        
        
    }
    
    //TODO: - 数组变形
    func arrayMap() {
        let fibs = [1, 2, 3, 4, 5]
        var squared:[Int] = []
        for fib in fibs {
            squared.append(fib * fib)
        }
        print(squared)//[1, 4, 9, 16, 25]
        print("---------------------------------------")

        let squared1 = fibs.map { (fib) -> Int in
            fib * fib
        }
        print(squared1)//[1, 4, 9, 16, 25]
        print("---------------------------------------")

        let squared3 = fibs.map { (fib) -> String in
            "\(fib * fib)"
        }
        print(squared3)//[1, 4, 9, 16, 25]
        
        print("---------------------------------------")
        
        let fibs1 = ["My", "name", "is", "da", "shuai", "B"]
        let squared2 = fibs1.map { (fib) -> Int in
            fib.count
        }
        print(squared2)
        print("---------------------------------------")

        let fibs2 = ["My", "name", "is", "da", "shuai", "B"]
        let squared4 = fibs2.map { $0.count }
        print(squared4)
        print("---------------------------------------")
        
        
        let arr = [1, 4, 9, 16, 25]
        let tempArr = arr.map { "NO.\(String($0))" }
        print(tempArr)//["NO.1", "NO.4", "NO.9", "NO.16", "NO.25"]
        
        print("---------------------------------------")

//        let arr1 = [["My", "name", "is", "da", "shuai", "B"], ["My", "name", "is", "da", "shuai", "B"]]
//        let tempArr1 = arr1.flatMap { $0 }
//        let temp1 = arr1.flatMap { (<#[String]#>) -> Sequence in
//            <#code#>
//        }
        
//        print(tempArr1)//["My", "name", "is", "da", "shuai", "B", "My", "name", "is", "da", "shuai", "B"]
        
        print("---------------------------------------")

        let arr2 = [1, 4, 9, 16, 25]
        let tempArr2 = arr2.map { (a) -> String in
            "\(a * a)"
        }
        print(tempArr2)
        
        var arr3 = [2,1,4,13,64,33,5]
        arr3.sort{ ($0) > $1 }
        print(arr3)//[64, 33, 13, 5, 4, 2, 1]
        print("---------------------------------------")
        
        var arr4 = ["My", "name", "is", "da", "shuai", "B"]
        arr4.sort()
        print(arr4)  //["B", "My", "da", "is", "name", "shuai"]
        
        
    }
    
    func changeArray() {
        let arr = [1,2,3,4,1,1]
        let temp = arr.filter { $0 == 5 || $0 == 1 }
        let tempA = ["My", "name", "is", "da", "shuai", "B"].filter { (a) -> Bool in
            a.count == 2 || a.elementsEqual("B")
        }
        print(temp , tempA)
        print("---------------------------------------")
        
        let x = arr.reduce(0, { $0 + $1 })
        print(x)
        
        let y = arr.reduce(1, { (a, b) -> Int in
            a - b
        })
        print(y)
        
        let z = arr.reduce(into: [:]) { (c, a) in
            c[1, default: 0] += 1
        }
        print(z)
        
        var c: Int = 0
        let w = arr.reduce(into: String()) { (a, b) in
            c = (b == 1) ? (c+1) : (c+0)
            a = "\(c)"
        }
        print("\(w)")
    }
}

extension Array {
    
    /*
     * Element 是数组中包含的元素类型的占位符
     * T 是元素转换之后的类型的占位符
     * T 的具体类型将由调用者传入给 map 的 transform 方法的返回值类型来决定。
     */
//    func map<T>(_ transform: (Element) -> T) -> [T] {
//        var result: [T] = []
//        result.reserveCapacity(count)
//        for x in self {
//            result.append(transform(x))
//        }
//        return result;
//    }
}

